home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / hAWK project / AWK Source / IO.C < prev    next >
Text File  |  1995-04-08  |  20KB  |  870 lines

  1. /*
  2.  * IO.C - routines for dealing with input and output and records
  3.  */
  4. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  5.  *         This file is part of GAWK, the GNU implementation of the
  6.  * AWK Progamming Language, modified for the Macintosh (also called hAWK).
  7.  *         GAWK is free software; you can redistribute or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 1, or any later version.
  10.  *         GAWK is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  * GNU General Public License for more details.
  14.  *         You should have received a copy of the GNU General Public License
  15.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  16.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  * Modified for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  18.  Revised Feb 93, do_getline.
  19.  */
  20.  
  21. #include "AWK.H"
  22.  
  23. /* The "Carriage Return" of the moment...*/
  24. #define CR '\n'
  25.  
  26. #ifndef O_RDONLY
  27. #include <fcntl.h>
  28. #endif
  29. #include <signal.h>
  30.  
  31. /* Global to indicate if calling app's event loop has been made
  32. available and should call it see Code_Main.c. Used in devopen below.*/
  33. extern Boolean gConcurrent;
  34.  
  35. /*IO.C*/
  36. static IOBUF *iop_alloc(FILE * fd);
  37. void do_input(void);
  38. static short iop_close(IOBUF *iop);
  39. static short inrec(IOBUF *iop);
  40. static void do_file(IOBUF *iop);
  41. char get_rs(void);
  42. struct redirect *redirect(NODE *tree, short *errflg);
  43. static void close_one(void);
  44. NODE *do_close(NODE *tree);
  45. static short close_redir(register struct redirect *rp);
  46. short flush_io (void);
  47. short close_io (void);
  48. FILE * devopen (char *name, char *mode);
  49. static IOBUF *gawk_popen(char *cmd, struct redirect *rp);
  50. static short gawk_pclose(struct redirect *rp);
  51. static void FixLineEnds(char *b, short l);
  52. static short get_a_record(char **res, IOBUF *iop);
  53. NODE *do_getline(NODE *tree);
  54. static IOBUF *nextfile(void);
  55.  
  56. static struct redirect *red_head = NULL;
  57. static short getline_redirect = 0;    /* "getline <file" being executed */
  58.  
  59. extern char *line_buf;
  60. extern short output_is_tty;
  61. extern NODE *ARGC_node;
  62. extern NODE *ARGV_node;
  63. extern NODE **fields_arr;
  64.  
  65. short field_num;
  66.  
  67.  
  68.  
  69. static IOBUF *iop_alloc(FILE * fd)
  70. {
  71.     IOBUF *iop;
  72. /*    struct stat stb;*/
  73.  
  74.     /*
  75.      * System V doesn't have the file system block size in the
  76.      * stat structure. So we have to make some sort of reasonable
  77.      * guess. We use stdio's BUFSIZ, since that is what it was
  78.      * meant for in the first place.
  79.      */
  80. #ifdef MACVERSION
  81. #define BLKSIZE_MISSING
  82. #endif
  83. #ifdef BLKSIZE_MISSING
  84. #define    DEFBLKSIZE    BUFSIZ
  85. #else
  86. #define DEFBLKSIZE    (stb.st_blksize ? stb.st_blksize : BUFSIZ)
  87. #endif
  88.  
  89.     if (fd == NULL)
  90.         return NULL;
  91.     emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile");
  92.     iop->flag = 0;
  93.     if (FALSE) {
  94.         iop->flag |= IOP_IS_TTY;
  95.         iop->size = BUFSIZ;
  96.     }
  97. #ifndef MACVERSION
  98.      else if (fstat(fd, &stb) == -1)
  99.         fatal("can't stat fd %d (%s)", fd, strerror(errno));
  100. #endif
  101.     else if (fseek(fd, 0L, 0) == -1)
  102.         iop->size = DEFBLKSIZE;
  103.     else
  104. #ifndef MACVERSION
  105.         iop->size = (stb.st_size < DEFBLKSIZE ?
  106.                 stb.st_size+1 : DEFBLKSIZE);
  107. #else
  108.     iop->size = DEFBLKSIZE;
  109. #endif
  110.     errno = 0;
  111.     iop->fd = fd;
  112.     emalloc(iop->buf, char *, iop->size, "nextfile");
  113.     iop->off = iop->buf;
  114.     iop->cnt = 0;
  115.     iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ;
  116.     emalloc(iop->secbuf, char *, iop->secsiz, "nextfile");
  117.     return iop;
  118. }
  119.  
  120. void do_input()
  121. {
  122.     IOBUF *iop;
  123.     extern short exiting;
  124.  
  125.     while ((iop = nextfile()) != NULL) {
  126.         do_file(iop);
  127.         if (exiting)
  128.             break;
  129.     }
  130. }
  131.  
  132. static short iop_close(IOBUF *iop)
  133. {
  134.     short ret;
  135.  
  136.     ret = fclose(iop->fd);
  137.     if (ret == -1)
  138.         warning("close of file failed (%s)", strerror(errno));
  139.     free(iop->buf);
  140.     free(iop->secbuf);
  141.     free((char *)iop);
  142.     return ret == -1 ? 1 : 0;
  143. }
  144.  
  145. /*
  146.  * This reads in a record from the input file
  147.  */
  148. static short inrec(IOBUF *iop)
  149. {
  150.     short cnt;
  151.     short retval = 0;
  152.  
  153.     cnt = get_a_record(&line_buf, iop);
  154.     if (cnt == EOF) {
  155.         cnt = 0;
  156.         retval = 1;
  157.     } else {
  158.         if (!getline_redirect) {
  159.             assign_number(&NR_node->var_value,
  160.                 NR_node->var_value->numbr + 1.0);
  161.             assign_number(&FNR_node->var_value,
  162.                 FNR_node->var_value->numbr + 1.0);
  163.         }
  164.     }
  165.     set_record(line_buf, cnt);
  166.  
  167.     return retval;
  168. }
  169.  
  170. static void do_file(IOBUF *iop)
  171. {
  172.     /* This is where it spends all its time.  The infamous MAIN LOOP */
  173.     if (inrec(iop) == 0)
  174.         while (interpret(expression_value) && inrec(iop) == 0)
  175.             ;
  176.     (void) iop_close(iop);
  177. }
  178.  
  179. char get_rs()
  180. {
  181.     register NODE *tmp;
  182.  
  183.     tmp = force_string(RS_node->var_value);
  184.     if (tmp->stlen == 0)
  185.         return 0;
  186.     return *(tmp->stptr);
  187. }
  188.  
  189. /* Redirection for printf and print commands */
  190. struct redirect *redirect(NODE *tree, short *errflg)
  191. {
  192.     register NODE *tmp;
  193.     register struct redirect *rp;
  194.     register char *str;
  195.     short tflag = 0;
  196.     short outflag = 0;
  197.     char *direction = "to";
  198.     char *mode;
  199.     FILE * fd;
  200.  
  201.     switch (tree->type) {
  202.     case Node_redirect_append:
  203.         tflag = RED_APPEND;
  204.     case Node_redirect_output:
  205.         outflag = (RED_FILE|RED_WRITE);
  206.         tflag |= outflag;
  207.         break;
  208.     case Node_redirect_pipe:
  209.         tflag = (RED_PIPE|RED_WRITE);
  210.         break;
  211.     case Node_redirect_pipein:
  212.         tflag = (RED_PIPE|RED_READ);
  213.         break;
  214.     case Node_redirect_input:
  215.         tflag = (RED_FILE|RED_READ);
  216.         break;
  217.     default:
  218.         fatal ("invalid tree type %d in redirect()", tree->type);
  219.         break;
  220.     }
  221.     tmp = force_string(tree_eval(tree->subnode));
  222.     str = tmp->stptr;
  223.     for (rp = red_head; rp != NULL; rp = rp->next)
  224.         if (STREQ(rp->value, str)
  225.             && ((rp->flag & ~RED_NOBUF) == tflag
  226.             || (outflag
  227.                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
  228.             break;
  229.     if (rp == NULL) {
  230.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  231.             "redirect");
  232.         emalloc(str, char *, tmp->stlen+1, "redirect");
  233.         memcpy(str, tmp->stptr, tmp->stlen+1);
  234.         rp->value = str;
  235.         rp->flag = tflag;
  236.         rp->offset = 0;
  237.         rp->fp = NULL;
  238.         rp->iop = NULL;
  239.         /* maintain list in most-recently-used first order */
  240.         if (red_head)
  241.             red_head->prev = rp;
  242.         rp->prev = NULL;
  243.         rp->next = red_head;
  244.         red_head = rp;
  245.     }
  246.     while (rp->fp == NULL && rp->iop == NULL) {
  247.         mode = NULL;
  248.         errno = 0;
  249.         switch (tree->type) {
  250.         case Node_redirect_output:
  251.             mode = "w";
  252.             break;
  253.         case Node_redirect_append:
  254.             mode = "a";
  255.             break;
  256.         case Node_redirect_pipe:
  257.             if ((rp->fp = popen(str, "w")) == NULL)
  258.                 fatal("can't open pipe (\"%s\") for output (%s)",
  259.                     str, strerror(errno));
  260.             rp->flag |= RED_NOBUF;
  261.             break;
  262.         case Node_redirect_pipein:
  263.             direction = "from";
  264.             if (gawk_popen(str, rp) == NULL)
  265.                 fatal("can't open pipe (\"%s\") for input (%s)",
  266.                     str, strerror(errno));
  267.             break;
  268.         case Node_redirect_input:
  269.             direction = "from";
  270.             rp->iop = iop_alloc(devopen(str, "r"));
  271.             break;
  272.         default:
  273.             cant_happen();
  274.         }
  275.         if (mode != NULL) {
  276.             fd = devopen(str, mode);
  277.             if (fd != NULL) {
  278.                 rp->fp = fd;
  279.                 if (FALSE)
  280.                     rp->flag |= RED_NOBUF;
  281.             }
  282.         }
  283.         if (rp->fp == NULL && rp->iop == NULL) {
  284.             /* too many files open -- close one and try again */
  285.             if (errno /*== ENFILE || errno == EMFILE -- undef for MW */)
  286.                 close_one();
  287.             else {
  288.                 /*
  289.                  * Some other reason for failure.
  290.                  *
  291.                  * On redirection of input from a file,
  292.                  * just return an error, so e.g. getline
  293.                  * can return -1.  For output to file,
  294.                  * complain. The shell will complain on
  295.                  * a bad command to a pipe.
  296.                  */
  297.                 *errflg = 1;
  298.                 if (tree->type == Node_redirect_output
  299.                     || tree->type == Node_redirect_append)
  300.                     fatal("can't redirect %s %s (%s)",
  301.                         direction, str, strerror(errno));
  302.                 else
  303.                     return NULL;
  304.             }
  305.         }
  306.     }
  307.     if (rp->offset != 0)    /* this file was previously open */
  308.         if (fseek(rp->fp, rp->offset, 0) == -1)
  309.             fatal("can't seek to %ld on `%s' (%s)",
  310.                 rp->offset, str, strerror(errno));
  311.     free_temp(tmp);
  312.     return rp;
  313. }
  314.  
  315. static void close_one()
  316. {
  317.     register struct redirect *rp;
  318.     register struct redirect *rplast = NULL;
  319.  
  320.     /* go to end of list first, to pick up least recently used entry */
  321.     for (rp = red_head; rp != NULL; rp = rp->next)
  322.         rplast = rp;
  323.     /* now work back up through the list */
  324.     for (rp = rplast; rp != NULL; rp = rp->prev)
  325.         if (rp->fp && (rp->flag & RED_FILE)) {
  326.             rp->offset = ftell(rp->fp);
  327.             if (fclose(rp->fp))
  328.                 warning("close of \"%s\" failed (%s).",
  329.                     rp->value, strerror(errno));
  330.             rp->fp = NULL;
  331.             break;
  332.         }
  333.     if (rp == NULL)
  334.         /* surely this is the only reason ??? */
  335.         fatal("too many input files open"); 
  336. }
  337.  
  338. NODE *do_close(NODE *tree)
  339. {
  340.     NODE *tmp;
  341.     register struct redirect *rp;
  342.  
  343.     tmp = force_string(tree_eval(tree->subnode));
  344.     for (rp = red_head; rp != NULL; rp = rp->next) {
  345.         if (STREQ(rp->value, tmp->stptr))
  346.             break;
  347.     }
  348.     free_temp(tmp);
  349.     if (rp == NULL) /* no match */
  350.         return tmp_number((AWKNUM) 0.0);
  351.     fflush(stdout);    /* synchronize regular output */
  352.     return tmp_number((AWKNUM)close_redir(rp));
  353. }
  354.  
  355. static short close_redir(register struct redirect *rp)
  356. {
  357.     short status = 0;
  358.  
  359.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  360.         status = pclose(rp->fp);
  361.     else if (rp->fp)
  362.         status = fclose(rp->fp);
  363.     else if (rp->iop) {
  364.         if (rp->flag & RED_PIPE)
  365.             status = gawk_pclose(rp);
  366.         else
  367.             status = iop_close(rp->iop);
  368.  
  369.     }
  370.     /* SVR4 awk checks and warns about status of close */
  371.     if (status)
  372.         warning("failure status (%d) on %s close of \"%s\" (%s).",
  373.             status,
  374.             (rp->flag & RED_PIPE) ? "pipe" :
  375.             "file", rp->value, strerror(errno));
  376.     if (rp->next)
  377.         rp->next->prev = rp->prev;
  378.     if (rp->prev)
  379.         rp->prev->next = rp->next;
  380.     else
  381.         red_head = rp->next;
  382.     free(rp->value);
  383.     free((char *)rp);
  384.     return status;
  385. }
  386.  
  387. short flush_io ()
  388. {
  389.     register struct redirect *rp;
  390.     short status = 0;
  391.  
  392.     errno = 0;
  393.     if (fflush(stdout)) {
  394.         warning("error writing standard output (%s).", strerror(errno));
  395.         status++;
  396.     }
  397.     errno = 0;
  398.     if (fflush(stderr)) {
  399.         warning("error writing standard error (%s).", strerror(errno));
  400.         status++;
  401.     }
  402.     for (rp = red_head; rp != NULL; rp = rp->next)
  403.         /* flush both files and pipes, what the heck */
  404.         if ((rp->flag & RED_WRITE) && rp->fp != NULL)
  405.             if (fflush(rp->fp)) {
  406.                 warning("%s flush of \"%s\" failed (%s).",
  407.                     (rp->flag  & RED_PIPE) ? "pipe" :
  408.                     "file", rp->value, strerror(errno));
  409.                 status++;
  410.             }
  411.     return status;
  412. }
  413.  
  414. short close_io ()
  415. {
  416.     register struct redirect *rp;
  417.     short status = 0;
  418.  
  419.     for (rp = red_head; rp != NULL; rp = rp->next)
  420.         if (close_redir(rp))
  421.             status++;
  422.     return status;
  423. }
  424.  
  425. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  426. FILE * devopen (char *name, char *mode)
  427. {
  428.     short openfd = -1;
  429.     /*FILE *fdopen ();*/
  430.     char *cp;
  431.     short flag = 0;
  432.  
  433.     switch(mode[0]) {
  434.     case 'r':
  435.         if (!gConcurrent)
  436.             flag = O_RDONLY;
  437.         else
  438.             flag = O_RDWR;
  439.         break;
  440.  
  441.     case 'w':
  442.         flag = O_WRONLY|O_CREAT|O_TRUNC;
  443.         break;
  444.  
  445.     case 'a':
  446.         flag = O_WRONLY|O_APPEND|O_CREAT;
  447.         break;
  448.     default:
  449.         cant_happen();
  450.     }
  451. /* Mac note, "0666" means anyone can read/write - not supported by THINK C.*/
  452. #ifdef MACVERSION
  453.     if (STREQ(name, "stderr"))
  454.         return (stderr);
  455.     else if (STREQ(name, "stdout"))
  456.         return (stdout);
  457.     else
  458.         return (fopen (name, mode/*, 0666*/));
  459. #endif
  460. }
  461.  
  462. /* Mac note, pipes are not supported. */
  463. #ifndef MACVERSION
  464. #ifndef MSDOS
  465. static IOBUF *
  466. gawk_popen(cmd, rp)
  467. char *cmd;
  468. struct redirect *rp;
  469. {
  470.     short p[2];
  471.     register short pid;
  472.  
  473.     rp->pid = -1;
  474.     rp->iop = NULL;
  475.     if (pipe(p) < 0)
  476.         return NULL;
  477.     if ((pid = fork()) == 0) {
  478.         close(p[0]);
  479.         dup2(p[1], 1);
  480.         close(p[1]);
  481.         execl("/bin/sh", "sh", "-c", cmd, 0);
  482.         _exit(127);
  483.     }
  484.     if (pid == -1)
  485.         return NULL;
  486.     rp->pid = pid;
  487.     close(p[1]);
  488.     return (rp->iop = iop_alloc(p[0]));
  489. }
  490.  
  491. static short
  492. gawk_pclose(rp)
  493. struct redirect *rp;
  494. {
  495.     SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  496.     short pid;
  497.     short status;
  498.     struct redirect *redp;
  499.  
  500.     iop_close(rp->iop);
  501.     if (rp->pid == -1)
  502.         return rp->status;
  503.     hstat = signal(SIGHUP, SIG_IGN);
  504.     istat = signal(SIGINT, SIG_IGN);
  505.     qstat = signal(SIGQUIT, SIG_IGN);
  506.     for (;;) {
  507.         pid = wait(&status);
  508.         if (pid == -1 && errno == ECHILD)
  509.             break;
  510.         else if (pid == rp->pid) {
  511.             rp->pid = -1;
  512.             rp->status = status;
  513.             break;
  514.         } else {
  515.             for (redp = red_head; redp != NULL; redp = redp->next)
  516.                 if (pid == redp->pid) {
  517.                     redp->pid = -1;
  518.                     redp->status = status;
  519.                     break;
  520.                 }
  521.         }
  522.     }
  523.     signal(SIGHUP, hstat);
  524.     signal(SIGINT, istat);
  525.     signal(SIGQUIT, qstat);
  526.     return(rp->status);
  527. }
  528. #else
  529. static
  530. struct {
  531.     char *command;
  532.     char *name;
  533. } pipes[_NFILE];
  534.  
  535. static IOBUF *
  536. gawk_popen(cmd, rp)
  537. char *cmd;
  538. struct redirect *rp;
  539. {
  540.     extern char *strdup(const char *);
  541.     short current;
  542.     char *name;
  543.     static char cmdbuf[256];
  544.  
  545.     /* get a name to use.  */
  546.     if ((name = tempnam(".", "pip")) == NULL)
  547.         return NULL;
  548.     sprintf(cmdbuf,"%s > %s", cmd, name);
  549.     system(cmdbuf);
  550.     if ((current = open(name,O_RDONLY)) == -1)
  551.         return NULL;
  552.     pipes[current].name = name;
  553.     pipes[current].command = strdup(cmd);
  554.     return (rp->iop = iop_alloc(current));
  555. }
  556.  
  557. static short
  558. gawk_pclose(rp)
  559. struct redirect *rp;
  560. {
  561.     short cur = rp->iop->fd;
  562.     short rval;
  563.  
  564.     rval = iop_close(rp->iop);
  565.  
  566.     /* check for an open file  */
  567.     if (pipes[cur].name == NULL)
  568.         return -1;
  569.     unlink(pipes[cur].name);
  570.     free(pipes[cur].name);
  571.     pipes[cur].name = NULL;
  572.     free(pipes[cur].command);
  573.     return rval;
  574. }
  575. #endif
  576. #else
  577. /* here we are for the Mac version, alas... */
  578. static IOBUF *gawk_popen(char *cmd, struct redirect *rp)
  579. {
  580. return(NULL);
  581. }
  582.  
  583. static short gawk_pclose(struct redirect *rp)
  584. {
  585. return(1);
  586. }
  587.  
  588. #endif /* MACVERSION */
  589.  
  590. /* Mac version, or rather THINK C version, an admitted fudge to repair
  591. line ends. Some day I'll do a better job on this. Unless you do it first? */
  592. static void FixLineEnds(char *b, short l)
  593.     {
  594.     char *tPtr = b, *endPtr = b+l;
  595.     
  596.     while (tPtr < endPtr)
  597.         {
  598.         if (*tPtr == 0x0D)
  599.             *tPtr = '\n';
  600.         ++tPtr;
  601.         }
  602.     }
  603.  
  604. #define    DO_END_OF_BUF    len = (short)(bp - iop->off);\
  605.             used = (short)(last - start);\
  606.             while (len + used > iop->secsiz) {\
  607.                 iop->secsiz *= 2;\
  608.                 erealloc(iop->secbuf,char *,iop->secsiz,"get");\
  609.             }\
  610.             last = iop->secbuf + used;\
  611.             start = iop->secbuf;\
  612.             memcpy(last, iop->off, len);\
  613.             last += len;\
  614.             iop->cnt = fread(iop->buf, 1, (unsigned short)(iop->size), iop->fd);\
  615.             if (iop->cnt < 0)\
  616.                 return iop->cnt;\
  617.             FixLineEnds(iop->buf, iop->cnt);\
  618.             end_data = iop->buf + iop->cnt;\
  619.             iop->off = bp = iop->buf;
  620.  
  621. #define    DO_END_OF_DATA    iop->cnt = fread(end_data, 1, (unsigned short)(end_buf - end_data), iop->fd);\
  622.             if (iop->cnt < 0)\
  623.                 return iop->cnt;\
  624.             FixLineEnds(end_data, iop->cnt);\
  625.             end_data += iop->cnt;\
  626.             if (iop->cnt == 0)\
  627.                 break;\
  628.             iop->cnt = (short)(end_data - iop->buf);
  629.  
  630. static short get_a_record(char **res, IOBUF *iop)
  631. {
  632.     register char *end_data;
  633.     register char *end_buf;
  634.     char *start;
  635.     register char *bp;
  636.     register char *last;
  637.     short len, used;
  638.     register char rs = get_rs();
  639.     
  640.     if (iop->cnt < 0)
  641.         return iop->cnt;
  642.     if ((iop->flag & IOP_IS_TTY) && output_is_tty)
  643.         fflush(stdout);
  644.     end_data = iop->buf + iop->cnt;
  645.     if (iop->off >= end_data) {
  646.         iop->cnt = fread(iop->buf, 1, (unsigned short)(iop->size), iop->fd);
  647.         if (iop->cnt <= 0)
  648.             return iop->cnt = EOF;
  649.         FixLineEnds(iop->buf, iop->cnt);
  650.         end_data = iop->buf + iop->cnt;
  651.         iop->off = iop->buf;
  652.     }
  653.     last = start = bp = iop->off;
  654.     end_buf = iop->buf + iop->size;
  655.     if (rs == 0) {
  656.         while (!(*bp == CR && bp != iop->buf && bp[-1] == CR)) {
  657.             if (++bp == end_buf) {
  658.                 DO_END_OF_BUF
  659.             }
  660.             if (bp == end_data) {
  661.                 DO_END_OF_DATA
  662.             }
  663.         }
  664.         if (*bp == CR && bp != iop->off && bp[-1] == CR) {
  665.             short tmp = 0;
  666.  
  667.             /* allow for more than two newlines */
  668.             while (*bp == CR) {
  669.                 tmp++;
  670.                 if (++bp == end_buf) {
  671.                     DO_END_OF_BUF
  672.                 }
  673.                 if (bp == end_data) {
  674.                     DO_END_OF_DATA
  675.                 }
  676.             }
  677.             iop->off = bp;
  678.             bp -= 1 + tmp;
  679.         } else if (bp != iop->buf && bp[-1] != CR) {
  680.             warning("record not terminated");
  681.             iop->off = bp + 2;
  682.         } else {
  683.             bp--;
  684.             iop->off = bp + 2;
  685.         }
  686.     } else {
  687.         while (*bp++ != rs) {
  688.             if (bp == end_buf) {
  689.                 DO_END_OF_BUF
  690.             }
  691.             if (bp == end_data) {
  692.                 DO_END_OF_DATA
  693.             }
  694.         }
  695.         if (*--bp != rs) {
  696.             warning("record not terminated");
  697.             bp++;
  698.         }
  699.         iop->off = bp + 1;
  700.     }
  701.     if (start == iop->secbuf) {
  702.         len = (short)(bp - iop->buf);
  703.         if (len > 0) {
  704.             used = (short)(last - start);
  705.             while (len + used > iop->secsiz) {
  706.                 iop->secsiz *= 2;
  707.                 erealloc(iop->secbuf,char *,iop->secsiz,"get2");
  708.             }
  709.             last = iop->secbuf + used;
  710.             start = iop->secbuf;
  711.             memcpy(last, iop->buf, len);
  712.             last += len;
  713.         }
  714.     } else
  715.         last = bp;
  716.     *last = '\0';
  717.     *res = start;
  718.     return ((short)(last - start));
  719. }
  720.  
  721. /* Revised Feb 93 - assign_number calls moved lower since they
  722. were interfering with do_deref. */
  723. NODE *do_getline(NODE *tree)
  724. {
  725.     struct redirect *rp;
  726.     IOBUF *iop;
  727.     short cnt;
  728.     NODE **lhs;
  729.     short redir_error = 0;
  730.  
  731.     if (tree->rnode == NULL) {     /* no redirection */
  732.         iop = nextfile();
  733.         if (iop == NULL)        /* end of input */
  734.             return tmp_number((AWKNUM) 0.0);
  735.     } else {
  736.         rp = redirect(tree->rnode, &redir_error);
  737.         if (rp == NULL && redir_error)    /* failed redirect */
  738.             return tmp_number((AWKNUM) -1.0);
  739.         iop = rp->iop;
  740.         getline_redirect++;
  741.     }
  742.     if (tree->lnode == NULL) {    /* no optional var. -- read in $0 */
  743.         if (inrec(iop) != 0) {
  744.             getline_redirect = 0;
  745.             return tmp_number((AWKNUM) 0.0);
  746.         }
  747.     } else {            /* read in a named variable */
  748.         char *s = NULL;
  749.  
  750.         lhs = get_lhs(tree->lnode, 1);
  751.         cnt = get_a_record(&s, iop);
  752.         if (cnt == EOF) {
  753.             if (!getline_redirect) {
  754.                 assign_number(&NR_node->var_value,
  755.                     NR_node->var_value->numbr + 1.0);
  756.                 assign_number(&FNR_node->var_value,
  757.                     FNR_node->var_value->numbr + 1.0);
  758.             }
  759.             getline_redirect = 0;
  760.             free(s);
  761.             return tmp_number((AWKNUM) 0.0);
  762.         }
  763.         *lhs = make_string(s, strlen(s));
  764.         do_deref();
  765.         if (!getline_redirect) {
  766.             assign_number(&NR_node->var_value,
  767.                 NR_node->var_value->numbr + 1.0);
  768.             assign_number(&FNR_node->var_value,
  769.                 FNR_node->var_value->numbr + 1.0);
  770.         }
  771.         /* we may have to regenerate $0 here! */
  772.         if (field_num == 0)
  773.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  774.         field_num = -1;
  775.     }
  776.     getline_redirect = 0;
  777.     return tmp_number((AWKNUM) 1.0);
  778. }
  779.  
  780. static short si = 1;
  781. static short files = 0;
  782. static IOBUF *curfile = NULL;
  783.  
  784. static IOBUF *nextfile()
  785. {
  786.     
  787.     char *arg;
  788.     char *cp;
  789.     FILE * fd = NULL;
  790.  
  791.     if (curfile != NULL && curfile->cnt != EOF)
  792.         return curfile;
  793.     /* NOTE si is static */
  794.     for (; si < (short) (ARGC_node->lnode->numbr); si++) {
  795.         arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) si)))->stptr;
  796.         if (*arg == '\0')
  797.             continue;
  798.         cp = strchr(arg, '=');
  799.         if (cp != NULL) {
  800.             *cp++ = '\0';
  801.             variable(arg)->var_value = make_string(cp, strlen(cp));
  802.             *--cp = '=';    /* restore original text of ARGV */
  803.         } else {
  804.             files++;
  805.             if (STREQ(arg, "-"))
  806.                 fd = stdin;
  807.             else
  808.                 fd = devopen(arg, "r");
  809.             if (fd == NULL)
  810.                 fatal("cannot open file `%s' for reading (%s)",
  811.                     arg, strerror(errno));
  812.                 /* NOTREACHED */
  813.             /* This is a kludge.  */
  814.             deref = FILENAME_node->var_value;
  815.             do_deref();
  816.             FILENAME_node->var_value =
  817.                 make_string(arg, strlen(arg));
  818.             FNR_node->var_value->numbr = 0.0;
  819.             si++;
  820.             break;
  821.         }
  822.     }
  823.     if (files == 0) {
  824.         files++;
  825.         /* no args. -- use stdin */
  826.         /* FILENAME is init'ed to "-" */
  827.         /* FNR is init'ed to 0 */
  828.         fd = stdin;
  829.     }
  830.     if (fd == NULL)
  831.         return NULL;
  832.     return curfile = iop_alloc(fd);
  833. }
  834.  
  835. void InitIO(void);
  836.  
  837. void InitIO()
  838.     {
  839.     if (!hAWKstackDepth)
  840.         red_head = NULL;
  841.     getline_redirect = 0;    /* "getline <file" being executed */
  842.     field_num = 0;
  843.     /* in nextfile:*/
  844.         si = 1;
  845.         files = 0;
  846.         curfile = NULL;
  847.     }
  848.  
  849. void SaveIO(void);
  850. void RestoreIO(void);
  851. void SaveIO()
  852.     {
  853.     hs->red_head = red_head;
  854.     hs->getline_redirect = getline_redirect;
  855.     hs->field_num = field_num;
  856.     hs->si = si;
  857.     hs->files = files;
  858.     hs->curfile = curfile;
  859.     }
  860.  
  861. void RestoreIO()
  862.     {
  863.     red_head = hs->red_head;
  864.     getline_redirect = hs->getline_redirect;
  865.     field_num = hs->field_num;
  866.     si = hs->si;
  867.     files = hs->files;
  868.     curfile = hs->curfile;
  869.     }
  870.